﻿using DevExpress.XtraEditors;

using DevTeamIT;
//using Impinj.OctaneSdk;
using Org.LLRP.LTK.LLRPV1;
using Org.LLRP.LTK.LLRPV1.DataType;
using Org.LLRP.LTK.LLRPV1.Impinj;
using System;
using System.IO;

namespace ConfExpert.Forms.Base
{
    public partial class XRFID : XForm
    {
        public XRFID()
        {
            InitializeComponent();
        }

        private void XRFID_Load(object sender, EventArgs e)
        {
            this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(XRFID_FormClosing);
        }

        void XRFID_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            CloseReader();
        }

        public void StartReader(string readerName, ENUM_ImpinjInventorySearchType search)
        {
            InitializeReader(readerName, search);
        }

        bool inventory = false;
        //public void StartInventory()
        //{
        //    //btnInv.Enabled = false;  

        //    if (!inventory)
        //    {
        //        Set_Reader_Config();   // Sets the client configuration

        //        Add_RoSpec();
        //        //Application.DoEvents();
        //        Enable_RoSpec();
        //        Start_RoSpec();
        //        inventory = true;
        //    }
        //}

        //public void StopInventory()
        //{
        //    if (inventory)
        //    {
        //        Stop_RoSpec();
        //        Delete_RoSpec();
        //        inventory = false;
        //    }
        //}


        string epc;
        int eventCount = 0;
        //int txPwrIndx = 0;
        //int ChannelIndex = 0;
        //int hopTableID = 0;
        //UInt32 modelNumber = 0;
        public ushort AntennaId = 0;

        delegate void AddTagLCallback(MSG_RO_ACCESS_REPORT msg);
        void reader_OnRoAccessReportReceived(MSG_RO_ACCESS_REPORT msg)
        {
            Invoke(new AddTagLCallback(AddTag), msg);
        }

        void AddTag(MSG_RO_ACCESS_REPORT msg)
        {
            if (msg.TagReportData != null)
                for (int i = 0; i < msg.TagReportData.Length; i++)
                {
                    AntennaId = msg.TagReportData[i].AntennaID.AntennaID;
                    //sbyte PeakRSSI = msg.TagReportData[i].PeakRSSI.PeakRSSI;

                    // Two possible types of EPC: 96-bit and 128-bit
                    if (msg.TagReportData[i].EPCParameter[0].GetType() == typeof(PARAM_EPC_96))
                        epc = ((PARAM_EPC_96)(msg.TagReportData[i].EPCParameter[0])).EPC.ToHexString().TrimStart('0'); //ToHexString idi!
                    else
                        epc = ((PARAM_EPCData)(msg.TagReportData[i].EPCParameter[0])).EPC.ToHexString().TrimStart('0');


                    if (epc.Length >= 12)
                        Notify(epc);
                    else
                        if (intParse(epc) > 0)
                            AddTag(intParse(epc), AntennaId);
                        else
                            Notify(epc);

                }
        }

        public virtual void AddTag(int epcint, ushort AntennaId)
        {
        }

        //LLRP Reader Mode (Mode Index) Values 
        //1000 AutoSet Dense Interrogator 
        //1001 AutoSet Single Interrogator 
        //0 High Speed 640k bps 
        //1 Hybrid 80k/160k bps 
        //2 Dense Reader M=4 HiSpd 
        //3 Dense Reader M=8 LoSpd 
        //4 Dense Reader MaxMiller 
        // Simple Handler for receiving the reader events from the reader
        void reader_OnReaderEventNotification(MSG_READER_EVENT_NOTIFICATION msg)
        {
            // Events could be empty
            if (msg.ReaderEventNotificationData == null) return;

            eventCount++;

            // speedway readers always report UTC timestamp
            UNION_Timestamp t = msg.ReaderEventNotificationData.Timestamp;
            PARAM_UTCTimestamp ut = (PARAM_UTCTimestamp)t[0];
            double millis = (ut.Microseconds + 500) / 1000;

            // LLRP reports time in microseconds relative to the Unix Epoch
            DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            DateTime now = epoch.AddMilliseconds(millis);

            // this is how you would look for individual events of interest
            // Here I just dump the event
            if (msg.ReaderEventNotificationData.AISpecEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.AISpecEvent.ToString());
            if (msg.ReaderEventNotificationData.AntennaEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.AntennaEvent.ToString());
            if (msg.ReaderEventNotificationData.ConnectionAttemptEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.ConnectionAttemptEvent.ToString());
            if (msg.ReaderEventNotificationData.ConnectionCloseEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.ConnectionCloseEvent.ToString());
            if (msg.ReaderEventNotificationData.GPIEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.GPIEvent.ToString());
            if (msg.ReaderEventNotificationData.HoppingEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.HoppingEvent.ToString());
            if (msg.ReaderEventNotificationData.ReaderExceptionEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.ReaderExceptionEvent.ToString());
            if (msg.ReaderEventNotificationData.ReportBufferLevelWarningEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.ReportBufferLevelWarningEvent.ToString());
            if (msg.ReaderEventNotificationData.ReportBufferOverflowErrorEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.ReportBufferOverflowErrorEvent.ToString());
            if (msg.ReaderEventNotificationData.ROSpecEvent != null)
                XtraMessageBox.Show(msg.ReaderEventNotificationData.ROSpecEvent.ToString());
        }


        public ENUM_ImpinjInventorySearchType search
        {
            get;
            set;
        }

        LLRPClient reader;
        void InitializeReader(string readerName, ENUM_ImpinjInventorySearchType search)
        {
            this.search = search;
            if (!inventory)
                try
                {
                    #region Initializing
                    {
                        //Create an instance of LLRP reader client.
                        reader = new LLRPClient();

                        //Impinj Best Practice! Always Install the Impinj extensions
                        Impinj_Installer.Install();
                    }
                    #endregion

                    #region EventHandlers
                    {
                        //reader.OnReaderEventNotification += new delegateReaderEventNotification(reader_OnReaderEventNotification);
                        reader.OnRoAccessReportReceived += new delegateRoAccessReport(reader_OnRoAccessReportReceived);
                    }
                    #endregion

                    #region Connecting
                    {
                        ENUM_ConnectionAttemptStatusType status;

                        //Open the reader connection.  Timeout after 5 seconds
                        reader.Open(readerName, 5000, out status);

                        //Ensure that the open succeeded and that the reader
                        // returned the correct connection status result

                        if (status != ENUM_ConnectionAttemptStatusType.Success)
                        {
                            XtraMessageBox.Show("Failed to Connect to Reader \n");
                            return;
                        }
                    }
                    #endregion

                    #region EnableExtensions
                    {
                        MSG_IMPINJ_ENABLE_EXTENSIONS imp_msg = new MSG_IMPINJ_ENABLE_EXTENSIONS();
                        MSG_ERROR_MESSAGE msg_err;

                        imp_msg.MSG_ID = 1; //  this doesn't need to be set as the library will default

                        //Send the custom message and wait for 8 seconds
                        MSG_CUSTOM_MESSAGE cust_rsp = reader.CUSTOM_MESSAGE(imp_msg, out msg_err, 8000);
                        MSG_IMPINJ_ENABLE_EXTENSIONS_RESPONSE msg_rsp = cust_rsp as MSG_IMPINJ_ENABLE_EXTENSIONS_RESPONSE;

                        if (msg_rsp != null)
                        {
                            if (msg_rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                            {
                                XtraMessageBox.Show(msg_rsp.LLRPStatus.StatusCode.ToString());
                                reader.Close();
                                return;
                            }
                        }
                        else if (msg_err != null)
                        {
                            XtraMessageBox.Show(msg_err.ToString());
                            reader.Close();
                            return;
                        }
                        else
                        {
                            XtraMessageBox.Show("Enable Extensions Command Timed out\n");
                            reader.Close();
                            return;
                        }
                    }
                    #endregion

                    #region FactoryDefault
                    {
                        // factory default the reader
                        MSG_SET_READER_CONFIG msg_cfg = new MSG_SET_READER_CONFIG();
                        MSG_ERROR_MESSAGE msg_err;

                        msg_cfg.ResetToFactoryDefault = true;
                        msg_cfg.MSG_ID = 2; //this doesn't need to be set as the library will default

                        //if SET_READER_CONFIG affects antennas it could take several seconds to return
                        MSG_SET_READER_CONFIG_RESPONSE rsp_cfg = reader.SET_READER_CONFIG(msg_cfg, out msg_err, 12000);

                        if (rsp_cfg != null)
                        {
                            if (rsp_cfg.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                            {
                                XtraMessageBox.Show(rsp_cfg.LLRPStatus.StatusCode.ToString());
                                reader.Close();
                                return;
                            }
                        }
                        else if (msg_err != null)
                        {
                            XtraMessageBox.Show(msg_err.ToString());
                            reader.Close();
                            return;
                        }
                        else
                        {
                            XtraMessageBox.Show("SET_READER_CONFIG Command Timed out\n");
                            reader.Close();
                            return;
                        }
                    }
                    #endregion
                    /*
                #region getReaderCapabilities
                {
                    MSG_GET_READER_CAPABILITIES cap = new MSG_GET_READER_CAPABILITIES();
                    cap.MSG_ID = 2; // not this doesn't need to bet set as the library will default
                    cap.RequestedData = ENUM_GetReaderCapabilitiesRequestedData.All;

                    //Send the custom message and wait for 8 seconds
                    MSG_ERROR_MESSAGE msg_err;
                    MSG_GET_READER_CAPABILITIES_RESPONSE msg_rsp = reader.GET_READER_CAPABILITIES(cap, out msg_err, 8000);

                    if (msg_rsp != null)
                    {
                        if (msg_rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                        {
                            XtraMessageBox.Show(msg_rsp.LLRPStatus.StatusCode.ToString());
                            reader.Close();
                            return;
                        }
                    }
                    else if (msg_err != null)
                    {
                        XtraMessageBox.Show(msg_err.ToString());
                        reader.Close();
                        return;
                    }
                    else
                    {
                        XtraMessageBox.Show("GET reader Capabilities Command Timed out\n");
                        reader.Close();
                        return;
                    }

                    // Get the reader model number since some features are not
                    // available on Speedway revolution.
                    //PARAM_GeneralDeviceCapabilities dev_cap = msg_rsp.GeneralDeviceCapabilities;

                    // Check to make sure the model number mathces and that this device
                    // is an impinj reader (deviceManufacturerName == 25882)
                    //if ((dev_cap != null) &&
                    //    (dev_cap.DeviceManufacturerName == 25882))
                    //{
                    //    modelNumber = dev_cap.ModelName;
                    //}
                    //else
                    //{
                    //    XtraMessageBox.Show("Could not determine reader model number\n");
                    //    reader.Close();
                    //    return;
                    //}


                    // get the uhf band capabilities.  Inside this is the power table.
                    // take the last element of the power table to get the highest power.
                    PARAM_UHFBandCapabilities uhf = msg_rsp.RegulatoryCapabilities.UHFBandCapabilities;
                    PARAM_TransmitPowerLevelTableEntry entry = uhf.TransmitPowerLevelTableEntry[uhf.TransmitPowerLevelTableEntry.Length - 1];
                    txPwrIndx = entry.Index;    //TODO: 91 mi?
                    //power = entry.TransmitPowerValue / 100;

                    //XtraMessageBox.Show("     Max Power " + power.ToString() + " dbm.");
                }
                #endregion
                
                #region getReaderConfig
                {
                    MSG_GET_READER_CONFIG cap = new MSG_GET_READER_CONFIG();
                    cap.MSG_ID = 2; // not this doesn't need to be set as the library will default
                    cap.RequestedData = ENUM_GetReaderConfigRequestedData.All;

                    //Send the custom message and wait for 8 seconds
                    MSG_ERROR_MESSAGE msg_err;
                    MSG_GET_READER_CONFIG_RESPONSE msg_rsp = reader.GET_READER_CONFIG(cap, out msg_err, 8000);

                    if (msg_rsp != null)
                    {
                        if (msg_rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                        {
                            XtraMessageBox.Show(msg_rsp.LLRPStatus.StatusCode.ToString());
                            reader.Close();
                            return;
                        }
                    }
                    else if (msg_err != null)
                    {
                        XtraMessageBox.Show(msg_err.ToString());
                        reader.Close();
                        return;
                    }
                    else
                    {
                        XtraMessageBox.Show("GET reader Config Command Timed out\n");
                        reader.Close();
                        return;
                    }

                    // Get the hopTableId and Channel Index
                    if ((null != msg_rsp.AntennaConfiguration)
                        && (0 < msg_rsp.AntennaConfiguration.Length)
                        && (null != msg_rsp.AntennaConfiguration[0].RFTransmitter))
                    {
                        PARAM_RFTransmitter rftx = msg_rsp.AntennaConfiguration[0].RFTransmitter;

                        // we have to get these two values as well otherwise
                        // we won't know what to fill in the RFTransmitter
                        // parameter when we set transmit power
                        
                        

                        ChannelIndex = rftx.ChannelIndex;   //TODO: bunları öğrendikten sonra buraları kapat!
                        hopTableID = rftx.HopTableID;
                    }
                    else
                    {
                        XtraMessageBox.Show("Could not get rf transmitter parameters\n");
                        reader.Close();
                        return;
                    }

                    //msg_rsp.AntennaConfiguration[0].RFReceiver = new PARAM_RFReceiver();
                    // Receiver sensitivity
                    //msg_rsp.AntennaConfiguration[0].RFReceiver.ReceiverSensitivity = 1; //the most sensitive

                }
                #endregion
                */


                    SetReaderConfigWithXML();   // sets the client configuration
                    AddRoSpecWithXML();
                    //Application.DoEvents();
                    Enable_RoSpec();
                    Start_RoSpec();
                    inventory = true;
                }
                catch (Exception Ex)
                {
                    throw Ex;
                }
        }





        void SetReaderConfigWithXML()
        {
           // Org.LLRP.LTK.LLRPV1.DataType.Message obj;
            /*
            ENUM_LLRP_MSG_TYPE msg_type;
            
            // read the XML from a file and validate its an SET_READER_CONFIG
            try
            {
                FileStream fs = new FileStream(Session.AppDataPath + @"\setReaderConfig.token", FileMode.Open);
                StreamReader sr = new StreamReader(fs);
                string s = sr.ReadToEnd();
                fs.Close();

                LLRPXmlParser.ParseXMLToLLRPMessage(s, out obj, out msg_type);

                if (obj == null || msg_type != ENUM_LLRP_MSG_TYPE.SET_READER_CONFIG)
                {
                    throw new Exception();
                    //XtraMessageBox.Show("Could not extract message from XML");
                    //reader.Close();
                    //return;
                }
            }
            catch
                */
            {
                SetReaderConfig();
                //XtraMessageBox.Show("Unable to convert to valid XML");
                //reader.Close();
                return;
            }

            /* unreachable code
            // Communicate that message to the reader
            MSG_SET_READER_CONFIG msg = (MSG_SET_READER_CONFIG)obj;

            // set the max power available but don' forget to
            // apply the hoptable and channelIndex from the
            // current configuration
            //PARAM_AntennaConfiguration ant = msg.AntennaConfiguration[0];   //TODO: sadece birinci anten mi, yoksa hepsi birden mi?
            //ant.RFTransmitter.TransmitPower = 87;   // (ushort)txPwrIndx;    //91 mi?
            //ant.RFTransmitter.ChannelIndex = 1; // (ushort)ChannelIndex;
            //ant.RFTransmitter.HopTableID = 0;   // (ushort)hopTableID;


            // enable tag direction if its a speedway R1000,
            // otherwise, print a warning and continue
            //if (modelNumber == 1000000)
            //{
            //    PARAM_ImpinjTagDirectionReporting tagDir = new PARAM_ImpinjTagDirectionReporting();
            //    tagDir.EnableTagDirection = true;
            //    tagDir.AntennaConfiguration = ENUM_ImpinjTagDirectionAntennaConfiguration.Dual_Antenna;
            //    msg.ROReportSpec.AddCustomParameter(tagDir);
            //}

            MSG_ERROR_MESSAGE msg_err;
            MSG_SET_READER_CONFIG_RESPONSE rsp = reader.SET_READER_CONFIG(msg, out msg_err, 12000);
            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
            }
            else
            {
                XtraMessageBox.Show("SET_READER_CONFIG Command Timed out\n");
                reader.Close();
            }              
               */
        }

        void AddRoSpecWithXML()
        {
            Org.LLRP.LTK.LLRPV1.DataType.Message obj;
            ENUM_LLRP_MSG_TYPE msg_type;

            // read the XML from a file and validate its an ADD_ROSPEC
            try
            {
                FileStream fs = new FileStream(Session.AppDataPath + @"\addRoSpec.xml", FileMode.Open);
                StreamReader sr = new StreamReader(fs);
                string s = sr.ReadToEnd();
                fs.Close();

                LLRPXmlParser.ParseXMLToLLRPMessage(s, out obj, out msg_type);

                if (obj == null || msg_type != ENUM_LLRP_MSG_TYPE.ADD_ROSPEC)
                {
                    throw new Exception();
                    //XtraMessageBox.Show("Could not extract message from XML");
                    //reader.Close();
                    //return;
                }
            }
            catch
            {
                Add_RoSpec();
                //XtraMessageBox.Show("Unable to convert to valid XML");
                //reader.Close();
                return;
            }

            // convert to the proper message type
            MSG_ADD_ROSPEC msg = (MSG_ADD_ROSPEC)obj;

            // Communicate that message to the reader
            MSG_ERROR_MESSAGE msg_err;
            MSG_ADD_ROSPEC_RESPONSE rsp = reader.ADD_ROSPEC(msg, out msg_err, 12000);
            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
            }
            else
            {
                XtraMessageBox.Show("ADD_ROSPEC Command Timed out\n");
                reader.Close();
            }
        }

        private void SetReaderConfig()
        {
            MSG_SET_READER_CONFIG msg = new MSG_SET_READER_CONFIG();

            msg.AntennaConfiguration = new PARAM_AntennaConfiguration[1];
            msg.AntennaConfiguration[0] = new PARAM_AntennaConfiguration();
            msg.AntennaConfiguration[0].AntennaID = 0;
            msg.AntennaConfiguration[0].AirProtocolInventoryCommandSettings = new UNION_AirProtocolInventoryCommandSettings();

            PARAM_C1G2InventoryCommand cmd = new PARAM_C1G2InventoryCommand();
            cmd.C1G2RFControl = new PARAM_C1G2RFControl();
            cmd.C1G2RFControl.ModeIndex = 1000;     //autoset
            cmd.C1G2RFControl.Tari = 0;

            cmd.C1G2SingulationControl = new PARAM_C1G2SingulationControl();
            cmd.C1G2SingulationControl.Session = new TwoBits(search == ENUM_ImpinjInventorySearchType.Dual_Target ? (ushort)2 : (ushort)1);
            cmd.C1G2SingulationControl.TagPopulation = 100; //bu değer nasıl?
            cmd.C1G2SingulationControl.TagTransitTime = 0;
            cmd.TagInventoryStateAware = false;

            PARAM_ImpinjInventorySearchMode search_mode = new PARAM_ImpinjInventorySearchMode();
            search_mode.InventorySearchMode = search;   //ENUM_ImpinjInventorySearchType.Single_Target_With_Suppression:ENUM_ImpinjInventorySearchType.Dual_Target;
            cmd.AddCustomParameter(search_mode);

            PARAM_ImpinjLowDutyCycle ldc = new PARAM_ImpinjLowDutyCycle();
            ldc.LowDutyCycleMode = ENUM_ImpinjLowDutyCycleMode.Enabled;
            ldc.EmptyFieldTimeout = (ushort)10000;
            ldc.FieldPingInterval = (ushort)200;
            cmd.AddCustomParameter(ldc);
            //Enable Low Duty Cycle when no tags are seen for 10 seconds.  Check antennas every 200 msec
            msg.AntennaConfiguration[0].AirProtocolInventoryCommandSettings.Add(cmd);

            msg.AntennaConfiguration[0].RFReceiver = new PARAM_RFReceiver();
            msg.AntennaConfiguration[0].RFReceiver.ReceiverSensitivity = 1;

            msg.AntennaConfiguration[0].RFTransmitter = new PARAM_RFTransmitter();
            msg.AntennaConfiguration[0].RFTransmitter.ChannelIndex = 3;     //3'tü!
            msg.AntennaConfiguration[0].RFTransmitter.HopTableID = 0;
            msg.AntennaConfiguration[0].RFTransmitter.TransmitPower = 87; //87;   // (ushort)txPwrIndx;

            msg.ROReportSpec = new PARAM_ROReportSpec();
            msg.ROReportSpec.N = 1;
            msg.ROReportSpec.ROReportTrigger = ENUM_ROReportTriggerType.Upon_N_Tags_Or_End_Of_ROSpec;
            msg.ROReportSpec.TagReportContentSelector = new PARAM_TagReportContentSelector();
            msg.ROReportSpec.TagReportContentSelector.AirProtocolEPCMemorySelector = new UNION_AirProtocolEPCMemorySelector();
            PARAM_C1G2EPCMemorySelector c1g2mem = new PARAM_C1G2EPCMemorySelector();
            c1g2mem.EnableCRC = false;
            c1g2mem.EnablePCBits = false;
            msg.ROReportSpec.TagReportContentSelector.AirProtocolEPCMemorySelector.Add(c1g2mem);

            msg.ROReportSpec.TagReportContentSelector.EnableAccessSpecID = false;
            msg.ROReportSpec.TagReportContentSelector.EnableAntennaID = true;
            msg.ROReportSpec.TagReportContentSelector.EnableChannelIndex = false;
            msg.ROReportSpec.TagReportContentSelector.EnableFirstSeenTimestamp = false;
            msg.ROReportSpec.TagReportContentSelector.EnableInventoryParameterSpecID = false;
            msg.ROReportSpec.TagReportContentSelector.EnableLastSeenTimestamp = false;
            msg.ROReportSpec.TagReportContentSelector.EnablePeakRSSI = false;
            msg.ROReportSpec.TagReportContentSelector.EnableROSpecID = false;
            msg.ROReportSpec.TagReportContentSelector.EnableSpecIndex = false;
            msg.ROReportSpec.TagReportContentSelector.EnableTagSeenCount = false;

            msg.ResetToFactoryDefault = false;

            MSG_ERROR_MESSAGE msg_err;
            MSG_SET_READER_CONFIG_RESPONSE rsp = reader.SET_READER_CONFIG(msg, out msg_err, 3000);

            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.ToString());
                    reader.Close();
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
            }
            else
            {
                XtraMessageBox.Show("setReaderConfig Timed out\n");
                reader.Close();
            }

        }


        private void Add_RoSpec()
        {
            MSG_ADD_ROSPEC msg = new MSG_ADD_ROSPEC();
            msg.ROSpec = new PARAM_ROSpec();
            msg.ROSpec.CurrentState = ENUM_ROSpecState.Disabled;
            msg.ROSpec.Priority = 0x00;
            msg.ROSpec.ROSpecID = 1034;

            msg.ROSpec.ROBoundarySpec = new PARAM_ROBoundarySpec();
            msg.ROSpec.ROBoundarySpec.ROSpecStartTrigger = new PARAM_ROSpecStartTrigger();
            msg.ROSpec.ROBoundarySpec.ROSpecStartTrigger.ROSpecStartTriggerType = ENUM_ROSpecStartTriggerType.Null;
            msg.ROSpec.ROBoundarySpec.ROSpecStopTrigger = new PARAM_ROSpecStopTrigger();
            msg.ROSpec.ROBoundarySpec.ROSpecStopTrigger.ROSpecStopTriggerType = ENUM_ROSpecStopTriggerType.Null;
            msg.ROSpec.ROBoundarySpec.ROSpecStopTrigger.DurationTriggerValue = 0;

            //msg.ROSpec.ROReportSpec = new PARAM_ROReportSpec();
            //msg.ROSpec.ROReportSpec.ROReportTrigger = ENUM_ROReportTriggerType.Upon_N_Tags_Or_End_Of_ROSpec;
            //msg.ROSpec.ROReportSpec.N = 1;

            //msg.ROSpec.ROReportSpec.TagReportContentSelector = new PARAM_TagReportContentSelector();
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableAccessSpecID = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableAntennaID = true;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableChannelIndex = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableFirstSeenTimestamp = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableInventoryParameterSpecID = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableLastSeenTimestamp = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnablePeakRSSI = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableROSpecID = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableSpecIndex = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.EnableTagSeenCount = false;

            //msg.ROSpec.ROReportSpec.TagReportContentSelector.AirProtocolEPCMemorySelector = new UNION_AirProtocolEPCMemorySelector();
            //PARAM_C1G2EPCMemorySelector c1g2mem = new PARAM_C1G2EPCMemorySelector();
            //c1g2mem.EnableCRC = false;
            //c1g2mem.EnablePCBits = false;
            //msg.ROSpec.ROReportSpec.TagReportContentSelector.AirProtocolEPCMemorySelector.Add(c1g2mem);

            //msg.ROSpec.SpecParameter = new UNION_SpecParameter();


            PARAM_AISpec aiSpec = new PARAM_AISpec();
            aiSpec.AntennaIDs = new UInt16Array();
            aiSpec.AntennaIDs.Add(0);   //applies to all antennas

            aiSpec.AISpecStopTrigger = new PARAM_AISpecStopTrigger();
            aiSpec.AISpecStopTrigger.AISpecStopTriggerType = ENUM_AISpecStopTriggerType.Null;
            aiSpec.AISpecStopTrigger.DurationTrigger = 0;

            aiSpec.InventoryParameterSpec = new PARAM_InventoryParameterSpec[1];
            aiSpec.InventoryParameterSpec[0] = new PARAM_InventoryParameterSpec();
            aiSpec.InventoryParameterSpec[0].InventoryParameterSpecID = 1234;
            aiSpec.InventoryParameterSpec[0].ProtocolID = ENUM_AirProtocols.EPCGlobalClass1Gen2;



            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration = new PARAM_AntennaConfiguration[1];      //?
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0] = new PARAM_AntennaConfiguration();

            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].AntennaID = 0;
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].RFTransmitter = new PARAM_RFTransmitter();
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].RFTransmitter.HopTableID = 0;  //0 değil mi?
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].RFTransmitter.ChannelIndex = 3;
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].RFTransmitter.TransmitPower = 87;  // (ushort)txPwrIndx;
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].RFReceiver = new PARAM_RFReceiver();
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].RFReceiver.ReceiverSensitivity = 1;


            //PARAM_C1G2InventoryCommand cmd = new PARAM_C1G2InventoryCommand();
            //cmd.C1G2RFControl = new PARAM_C1G2RFControl();
            //cmd.C1G2RFControl.ModeIndex = 1000;
            //cmd.C1G2RFControl.Tari = 0;
            //cmd.C1G2SingulationControl = new PARAM_C1G2SingulationControl();
            //cmd.C1G2SingulationControl.Session = new TwoBits(1);
            //cmd.C1G2SingulationControl.TagPopulation = 100;
            //cmd.C1G2SingulationControl.TagTransitTime = 0;
            //cmd.TagInventoryStateAware = false;

            //PARAM_ImpinjInventorySearchMode search_mode = new PARAM_ImpinjInventorySearchMode();
            //search_mode.InventorySearchMode = ENUM_ImpinjInventorySearchType.Single_Target;
            //cmd.AddCustomParameter(search_mode);

            //PARAM_ImpinjLowDutyCycle ldc = new PARAM_ImpinjLowDutyCycle();
            //ldc.LowDutyCycleMode = ENUM_ImpinjLowDutyCycleMode.Enabled;
            //ldc.EmptyFieldTimeout = (ushort)10000;
            //ldc.FieldPingInterval = (ushort)200;
            //cmd.AddCustomParameter(ldc);

            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].AirProtocolInventoryCommandSettings = new UNION_AirProtocolInventoryCommandSettings();
            //aiSpec.InventoryParameterSpec[0].AntennaConfiguration[0].AirProtocolInventoryCommandSettings.Add(cmd);


            msg.ROSpec.SpecParameter.Add(aiSpec);

            MSG_ERROR_MESSAGE msg_err;
            MSG_ADD_ROSPEC_RESPONSE rsp = reader.ADD_ROSPEC(msg, out msg_err, 12000);

            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.ToString());
                    reader.Close();
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
            }
            else
            {
                XtraMessageBox.Show("ADD_ROSPEC Command Timed out\n");
                reader.Close();
            }

        }



        private void Delete_RoSpec()
        {
            MSG_DELETE_ROSPEC msg = new MSG_DELETE_ROSPEC();
            MSG_ERROR_MESSAGE msg_err;
            msg.ROSpecID = 1034;   // Deletes ROSpec for the given id
            MSG_DELETE_ROSPEC_RESPONSE rsp = reader.DELETE_ROSPEC(msg, out msg_err, 3000);

            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                    return;
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
                return;
            }
            else
            {
                XtraMessageBox.Show("DELETE_ROSPEC Command Timed out\n");
                reader.Close();
                return;
            }
        }



        void Enable_RoSpec()
        {
            MSG_ENABLE_ROSPEC msg = new MSG_ENABLE_ROSPEC();
            MSG_ERROR_MESSAGE msg_err;
            msg.ROSpecID = 1034; // this better match the ROSpec we created above
            MSG_ENABLE_ROSPEC_RESPONSE rsp = reader.ENABLE_ROSPEC(msg, out msg_err, 12000);
            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                    return;
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
                return;
            }
            else
            {
                XtraMessageBox.Show("ENABLE_ROSPEC Command Timed out\n");
                reader.Close();
                return;
            }
        }

        void Start_RoSpec()
        {
            MSG_START_ROSPEC msg = new MSG_START_ROSPEC();
            MSG_ERROR_MESSAGE msg_err;
            msg.ROSpecID = 1034; // this better match the RoSpec we created above
            MSG_START_ROSPEC_RESPONSE rsp = reader.START_ROSPEC(msg, out msg_err, 12000);
            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                    return;
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
                return;
            }
            else
            {
                XtraMessageBox.Show("START_ROSPEC Command Timed out\n");
                reader.Close();
                return;
            }
        }

        void Stop_RoSpec()
        {
            MSG_STOP_ROSPEC msg = new MSG_STOP_ROSPEC();
            MSG_ERROR_MESSAGE msg_err;
            msg.ROSpecID = 1034; // this better match the RoSpec we created above
            MSG_STOP_ROSPEC_RESPONSE rsp = reader.STOP_ROSPEC(msg, out msg_err, 12000);
            if (rsp != null)
            {
                if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                    return;
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
                return;
            }
            else
            {
                XtraMessageBox.Show("STOP_ROSPEC Command Timed out\n");
                reader.Close();
                return;
            }
        }

        public void CloseReader()
        {
            /*
            // factory default the reader
            MSG_SET_READER_CONFIG msg_cfg = new MSG_SET_READER_CONFIG();
            MSG_ERROR_MESSAGE msg_err;

            msg_cfg.ResetToFactoryDefault = true;
            msg_cfg.MSG_ID = 2; // not this doesn't need to bet set as the library will default

            // Note that if SET_READER_CONFIG affects antennas it could take several seconds to return
            MSG_SET_READER_CONFIG_RESPONSE rsp_cfg = reader.SET_READER_CONFIG(msg_cfg, out msg_err, 12000);

            if (rsp_cfg != null)
            {
                if (rsp_cfg.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                {
                    XtraMessageBox.Show(rsp_cfg.LLRPStatus.StatusCode.ToString());
                    reader.Close();
                    return;
                }
            }
            else if (msg_err != null)
            {
                XtraMessageBox.Show(msg_err.ToString());
                reader.Close();
                return;
            }
            else
            {
                XtraMessageBox.Show("SET_READER_CONFIG Command Timed out\n");
                reader.Close();
                return;
            }
            */

            //XtraMessageBox.Show("  Received " + directionCount + " Direction Reports.");
            //XtraMessageBox.Show("  Received " + reportCount + " Tag Reports.");
            //XtraMessageBox.Show("  Received " + eventCount + " Events.");
            //XtraMessageBox.Show("Closing\n");




            // clean up the reader
            try
            {
                if (reader != null)
                {
                    reader.OnRoAccessReportReceived -= new delegateRoAccessReport(reader_OnRoAccessReportReceived);

                    // check if doing inventory
                    if (inventory)
                    {
                        Stop_RoSpec();
                        Delete_RoSpec();
                        inventory = false;
                    }
                    reader.Close();
                }
            }
            catch (Exception Ex)
            {
                throw Ex;
            }            
            //reader.OnReaderEventNotification -= new delegateReaderEventNotification(reader_OnReaderEventNotification);
        }

        public void Set_GPO_State(ushort port, bool state)
        {
            if (reader != null)
                if (reader.IsConnected)
                {
                    MSG_ERROR_MESSAGE msg_err;
                    MSG_SET_READER_CONFIG msg = new MSG_SET_READER_CONFIG();
                    // Build the message
                    msg.GPOWriteData = new PARAM_GPOWriteData[1];
                    msg.GPOWriteData[0] = new PARAM_GPOWriteData();
                    msg.GPOWriteData[0].GPOPortNumber = port;
                    msg.GPOWriteData[0].GPOData = state;
                    // Send the message
                    MSG_SET_READER_CONFIG_RESPONSE rsp = reader.SET_READER_CONFIG(msg, out msg_err, 2000);

                    if (rsp != null)
                    {
                        if (rsp.LLRPStatus.StatusCode != ENUM_StatusCode.M_Success)
                        {
                            XtraMessageBox.Show(rsp.LLRPStatus.StatusCode.ToString());
                        }
                    }
                    else if (msg_err != null)
                    {
                        XtraMessageBox.Show(msg_err.ToString());
                    }
                    else
                    {
                        XtraMessageBox.Show("Timeout Error.");
                    }
                }
        }

    }
}